package org.linjie.generate.core;

import org.linjie.generate.utils.MapUtils;
import org.linjie.generate.utils.ReadTextByLineUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static org.linjie.generate.utils.StringUtils.*;


/**
 * 生成器，入口
 */
@Component
public class GenerateCore {


    // 关键字，保留字
    private static Map<String, String> keywords = ReadTextByLineUtils.readByLocalResource("keywords.txt");

    private final static Logger logger = LoggerFactory.getLogger(GenerateCore.class);

    @Resource(name = "MysqlDatabaseInfoImpl")
    private DatabaseInfo databaseInfo;

    /**
     * 使用Freemarker进行渲染模板,可替换
     */
    @Resource(name = "RendererFreemarkerImpl")
    private Renderer renderer;

    @PostConstruct
    public void generate() {
        try {
            logger.info("开始生成");
            Connection conn = databaseInfo.getConnection();
            // 按照Table生成
            generateTableInfo(conn);
            // 按照View 生成
            generateViewInfo(conn);
            conn.close();
            logger.info("生成完成");
        } catch (SQLException e) {
            logger.error("出错了", e);
        }
    }


    /**
     * 根据表生成
     *
     * @param conn
     * @throws SQLException
     */
    void generateTableInfo(Connection conn) throws SQLException {
        logger.info("根据表生成");

        PreparedStatement ps = conn.prepareStatement(
                "select table_name,TABLE_COMMENT from information_schema.tables where table_schema='"
                        + databaseInfo.getDataSourceName()
                        + "' and table_type='base table'");
        generateByPreparedStatement(ps, conn);
        ps.close();
    }

    /**
     * 根据视图生成
     *
     * @param conn
     * @throws SQLException
     */
    void generateViewInfo(Connection conn) throws SQLException {
        logger.info("根据视图生成");
        PreparedStatement ps = conn.prepareStatement(
                "select table_name,TABLE_SCHEMA from information_schema.VIEWS where table_schema='"
                        + databaseInfo.getDataSourceName()
                        + "'");
        generateByPreparedStatement(ps, conn);
        ps.close();
    }

    void generateByPreparedStatement(PreparedStatement ps, Connection conn) throws SQLException {
        ResultSet rs = ps.executeQuery();
        Map<String, Object> params = new HashMap<>();
        while (rs.next()) {
            String tableName = rs.getString(1);
            String tableComment = rs.getString(2);
            String entityName = captureName(tableName);
            String minLineName = underline2midline(tableName);
            List<Map<String, Object>> columns = getColumnInfo(tableName, conn);
            params.put("tableName", tableName);
            params.put("entityName", entityName);
            params.put("minLineName", minLineName);
            params.put("tableComment", tableComment);
            params.put("columns", columns);
            // 渲染
            renderer.renderer(params);

        }
        rs.close();
    }

    /**
     * 根据表名生成列(字段)数据
     *
     * @param tableName
     * @param conn
     * @return
     * @throws SQLException
     */
    List<Map<String, Object>> getColumnInfo(String tableName, Connection conn) throws SQLException {
        PreparedStatement ps
                = conn.prepareStatement(
                "select column_name,column_type,column_comment,column_default " +
                        " from information_schema.columns " +
                        " where table_name='" + tableName + "'" +
                        " and   table_schema='" + databaseInfo.getDataSourceName() + "'");
        ResultSet rs = ps.executeQuery();
        List<Map<String, Object>> columns = new ArrayList<>();
        logger.info("生成:" + tableName + "");
        while (rs.next()) {
            String columnName = rs.getString(1);
            String columnType = rs.getString(2).toLowerCase();
            String columnComment = rs.getString(3);
            Object columnDefault = rs.getObject(4);
            String javaType = null;

            // 通用字段跳过
            if (columnName.equals("pk_id") || columnName.equals("create_time") || columnName.equals("last_modify_time") || columnName.equals("version") || columnName.equals("del_status")) {
                continue;
            }

            if (columnType.startsWith("int")) {
                javaType = "Integer";
            } else if (columnType.startsWith("datetime")) {
                javaType = "Date";
            } else if (columnType.startsWith("date")) {
                javaType = "Date";
            } else if (columnType.startsWith("bigint")) {
                javaType = "Long";
            } else if (columnType.startsWith("decimal")) {
                javaType = "BigDecimal";
            } else if (columnType.startsWith("float")) {
                javaType = "Float";
            } else if (columnType.startsWith("tinyint")) {
                javaType = "Boolean";
            } else {
                javaType = "String";
            }
            if (columnDefault == null) {
                columnDefault = "null";
            }
            String fieldName = underline2Camel(rs.getString(1), true);

            Map<String, Object> rows = MapUtils.builder()
                    .put("fieldName", fieldName) // 字段名
                    .put("fieldNameCapFirst", capFirst(fieldName)) // 字段名
                    .put("javaType", javaType) // 字段的Java类型
                    .put("comment", columnComment) // 备注
                    .put("isKeyword", keywords.get(fieldName.toLowerCase()) != null) // 是否是保留字
                    .put("defaultValue", columnDefault.toString()) // 默认值
                    .get();
            columns.add(rows);
        }
        return columns;

    }
}
